home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Software Money Savers / VirtualDub / Source / VirtualDub-1.7.7-src.7z / src / Asuka / source / glc.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-12-10  |  29.4 KB  |  1,259 lines

  1. //    Asuka - VirtualDub Build/Post-Mortem Utility
  2. //    Copyright (C) 2005-2006 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include "stdafx.h"
  19. #include <stdio.h>
  20. #include <exception>
  21. #include <hash_map>
  22. #include <vd2/system/error.h>
  23. #include <vd2/system/filesys.h>
  24. #include <vd2/system/vdalloc.h>
  25.  
  26. #include "utils.h"
  27. #include "glc.h"
  28.  
  29. using namespace GLCIL;
  30.  
  31. namespace {
  32.     enum {
  33.         kTokenIdent        = 256,
  34.         kTokenInteger,
  35.         kTokenDouble,
  36.         kTokenForeignCode,
  37.         kTokenCount
  38.     };
  39.  
  40. }
  41.  
  42. IGLCFragmentShader *CompileFragmentShaderNVRegisterCombiners(GLCErrorSink& errout, const GLCFragmentShader& shader, bool NV_register_combiners_2);
  43. IGLCFragmentShader *CompileFragmentShaderATIFragmentShader(GLCErrorSink& errout, const GLCFragmentShader& shader);
  44.  
  45. ///////////////////////////////////////////////////////////////////////////////
  46. struct GLCKeyword {
  47. public:
  48.     GLCKeyword(const char *s) : mpKeyword(s), mKeywordLen(strlen(s)) {}
  49.  
  50.     const char *mpKeyword;
  51.     int mKeywordLen;
  52. };
  53.  
  54. ///////////////////////////////////////////////////////////////////////////////
  55.  
  56. class GLCTokenizer : public GLCErrorSink {
  57. public:
  58.     GLCTokenizer();
  59.     ~GLCTokenizer();
  60.  
  61.     void Init(const char *srcName, const char *src, uint32 len);
  62.     int Token();
  63.     void Push(int tok) { mPushedToken = tok; }
  64.     void EnableNewlines(bool enable) { mbReturnNewlines = enable; }
  65.     void EnableForeignCode(bool enable) { mbReturnForeignCode = enable; }
  66.  
  67.     GLCCodeLocation GetLocation() const {
  68.         GLCCodeLocation loc = { mpSourceName, mLine, mpSrc - mpLineStart };
  69.         return loc;
  70.     }
  71.  
  72.     int GetInteger() const { return mTokenInt; }
  73.     double GetDouble() const { return mTokenDbl; }
  74.     const char *GetToken() const { return mpTokenStart; }
  75.     int GetTokenLen() const { return mTokenLen; }
  76.     int GetLineNumber() const { return mLine; }
  77.  
  78.     bool IsKeyword(const GLCKeyword& keyword) const;
  79.  
  80. protected:
  81.     bool mbReturnNewlines;
  82.     bool mbReturnForeignCode;
  83.     const char *mpSrc;
  84.     const char *mpSrcEnd;
  85.     const char *mpLineStart;
  86.     const char *mpSourceName;
  87.     const char *mpTokenStart;
  88.     int mTokenLen;
  89.     int mTokenInt;
  90.     int mPushedToken;
  91.     int mLine;
  92.     double mTokenDbl;
  93. };
  94.  
  95. GLCTokenizer::GLCTokenizer() {
  96. }
  97.  
  98. GLCTokenizer::~GLCTokenizer() {
  99. }
  100.  
  101. void GLCTokenizer::Init(const char *srcName, const char *src, uint32 len) {
  102.     mpSrc = src;
  103.     mpSrcEnd = src + len;
  104.     mpLineStart = src;
  105.     mpSourceName = srcName;
  106.     mLine = 1;
  107.     mPushedToken = 0;
  108.     mbReturnNewlines = false;
  109.     mbReturnForeignCode = false;
  110. }
  111.  
  112. int GLCTokenizer::Token() {
  113.     if (mPushedToken) {
  114.         int tok = mPushedToken;
  115.         mPushedToken = 0;
  116.         return tok;
  117.     }
  118.  
  119.     // skip whitespace and comments
  120.     char c;
  121.     for(;;) {
  122.         if (mpSrc == mpSrcEnd)
  123.             return 0;
  124.  
  125.         c = *mpSrc++;
  126.  
  127.         // skip whitespace
  128.         if (c == ' ' || c == '\t')
  129.             continue;
  130.  
  131.         // skip newlines
  132.         if (c == '\n' || c == '\r') {
  133.             ++mLine;
  134.  
  135.             if (mpSrc != mpSrcEnd && *mpSrc == (c ^ ('\n' ^ '\r')))
  136.                 ++mpSrc;
  137.  
  138.             mpTokenStart = mpSrc;
  139.             mTokenLen = 0;
  140.             mpLineStart = mpSrc;
  141.             if (mbReturnNewlines)
  142.                 return '\n';
  143.             else
  144.                 continue;
  145.         }
  146.  
  147.         // skip C++ style comments
  148.         if (c == '/' && mpSrc != mpSrcEnd && mpSrc[0] == '/') {
  149.             ++mpSrc;
  150.  
  151.             while(mpSrc != mpSrcEnd && *mpSrc != '\r' && *mpSrc != '\n')
  152.                 ++mpSrc;
  153.  
  154.             continue;
  155.         }
  156.  
  157.         break;
  158.     }
  159.  
  160.     mpTokenStart = mpSrc - 1;
  161.  
  162.     if (mbReturnForeignCode) {
  163.         int braceCount = 0;
  164.  
  165.         for(;;) {
  166.             if (mpSrc == mpSrcEnd)
  167.                 break;
  168.  
  169.             c = *mpSrc++;
  170.  
  171.             // skip whitespace
  172.             if (c == ' ' || c == '\t')
  173.                 continue;
  174.  
  175.             // skip newlines
  176.             if (c == '\n' || c == '\r') {
  177.                 ++mLine;
  178.  
  179.                 if (mpSrc != mpSrcEnd && *mpSrc == (c ^ ('\n' ^ '\r')))
  180.                     ++mpSrc;
  181.  
  182.                 mpLineStart = mpSrc;
  183.                 continue;
  184.             }
  185.  
  186.             // skip C++ style comments
  187.             if (c == '/' && mpSrc != mpSrcEnd && mpSrc[0] == '/') {
  188.                 ++mpSrc;
  189.  
  190.                 while(mpSrc != mpSrcEnd && *mpSrc != '\r' && *mpSrc != '\n')
  191.                     ++mpSrc;
  192.  
  193.                 continue;
  194.             }
  195.  
  196.             if (c == '{')
  197.                 ++braceCount;
  198.             else if (c == '}') {
  199.                 --braceCount;
  200.                 if (braceCount < 0) {
  201.                     --mpSrc;
  202.                     break;
  203.                 }
  204.             }
  205.         }
  206.  
  207.         mTokenLen = mpSrc - mpTokenStart;
  208.         return kTokenForeignCode;
  209.     }
  210.  
  211.     // check for integers
  212.     if (isdigit((unsigned char)c)) {
  213.         mTokenInt = c - '0';
  214.  
  215.         if (mpSrc != mpSrcEnd) {
  216.             do {
  217.                 c = *mpSrc;
  218.                 if (!isdigit((unsigned char)c))
  219.                     break;
  220.  
  221.                 mTokenInt = (mTokenInt * 10) + (c - '0');
  222.             } while(++mpSrc != mpSrcEnd);
  223.  
  224.             if (c == '.') {
  225.                 ++mpSrc;
  226.  
  227.                 // hmm, it's a double.
  228.                 while(mpSrc != mpSrcEnd && isdigit((unsigned char)*mpSrc))
  229.                     ++mpSrc;
  230.  
  231.                 if (mpSrc != mpSrcEnd) {
  232.                     c = *mpSrc;
  233.  
  234.                     if (c == 'e' || c == 'E') {
  235.                         ++mpSrc;
  236.                         if (mpSrc == mpSrcEnd)
  237.                             ThrowError("Invalid floating-point constant");
  238.  
  239.                         c = *mpSrc;
  240.                         if (c == '+' || c == '-')
  241.                             ++mpSrc;
  242.  
  243.                         if (mpSrc == mpSrcEnd || !isdigit((unsigned char)*mpSrc))
  244.                             ThrowError("Invalid floating-point constant");
  245.  
  246.                         do {
  247.                             ++mpSrc;
  248.                         } while(mpSrc != mpSrcEnd && isdigit((unsigned char)*mpSrc));
  249.                     }
  250.  
  251.                     if (mpSrc != mpSrcEnd && (*mpSrc == 'f' || *mpSrc == 'F'))
  252.                         ++mpSrc;
  253.                 }
  254.  
  255.                 mTokenLen = mpSrc - mpTokenStart;
  256.  
  257.                 std::string tmp(mpTokenStart, mpSrc);
  258.                 mTokenDbl = strtod(tmp.c_str(), NULL);
  259.  
  260.                 return kTokenDouble;
  261.             }
  262.         }
  263.  
  264.         mTokenLen = mpSrc - mpTokenStart;
  265.         return kTokenInteger;
  266.     }
  267.  
  268.     // check for identifiers
  269.     if (c == '_' || isalnum((unsigned char)c)) {
  270.         while(mpSrc != mpSrcEnd) {
  271.             c = *mpSrc;
  272.  
  273.             if (c != '_' && !isalnum((unsigned char)c))
  274.                 break;
  275.  
  276.             ++mpSrc;
  277.         }
  278.  
  279.         mTokenLen = mpSrc - mpTokenStart;
  280.         return kTokenIdent;
  281.     }
  282.  
  283.     // check for single char
  284.     if (strchr("{}(),.=;+-*/", c)) {
  285.         mTokenLen = 1;
  286.         return (unsigned char)c;
  287.     }
  288.  
  289.     if (isprint((unsigned char)c))
  290.         ThrowError("Unrecognized character '%c'", c);
  291.     else
  292.         ThrowError("Unrecognized character '0x%02x'", (unsigned char)c);
  293. }
  294.  
  295. bool GLCTokenizer::IsKeyword(const GLCKeyword& keyword) const {
  296.     return (mTokenLen == keyword.mKeywordLen && !memcmp(mpTokenStart, keyword.mpKeyword, mTokenLen));
  297. }
  298.  
  299. void GLCErrorSink::ThrowError(const char *format, ...) {
  300.     char buf[4096];
  301.     va_list val;
  302.  
  303.     va_start(val, format);
  304.     int cnt = _vsnprintf(buf, 4096, format, val);
  305.     va_end(val);
  306.  
  307.     if ((unsigned)cnt >= 4096)
  308.         buf[cnt] = 0;
  309.  
  310.     const GLCCodeLocation loc(GetLocation());
  311.     throw MyError("Shader compilation failed.\n%s(%d,%d): Error! %s", loc.mpFileName, loc.mLine, loc.mColumn, buf);
  312. }
  313.  
  314. void GLCErrorSink::ThrowError(const GLCCodeLocation& loc, const char *format, ...) {
  315.     char buf[4096];
  316.     va_list val;
  317.  
  318.     va_start(val, format);
  319.     int cnt = _vsnprintf(buf, 4096, format, val);
  320.     va_end(val);
  321.  
  322.     if ((unsigned)cnt >= 4096)
  323.         buf[cnt] = 0;
  324.  
  325.     throw MyError("Shader compilation failed.\n%s(%d,%d): Error! %s", loc.mpFileName, loc.mLine, loc.mColumn, buf);
  326. }
  327.  
  328. ///////////////////////////////////////////////////////////////////////////////
  329. class GLCCompiler {
  330. public:
  331.     GLCCompiler();
  332.     ~GLCCompiler();
  333.  
  334.     void Compile(const char *sourceName, const char *src, uint32 len, FILE *f);
  335.  
  336. protected:
  337.     void ParseTechnique();
  338.     void ParseFragmentShader(GLCFragmentShader& shader);
  339.     GLCDestArg ParseFragmentShaderDestination();
  340.     GLCSourceArg ParseFragmentShaderArgument();
  341.  
  342.     double    ParseConstantDoubleExpression();
  343.  
  344.     void Expect(int c);
  345.     VDNORETURN void Huh(const char *expected, int found);
  346.     std::string TokenName(int tok);
  347.  
  348.     GLCTokenizer    mLexer;
  349.     FILE *mpOutput;
  350.  
  351.     vdfastvector<IGLCFragmentShader *> mFragmentShaders;
  352.  
  353.     struct Technique {
  354.         IGLCFragmentShader *mpFragmentShader;
  355.     };
  356.  
  357.     typedef stdext::hash_map<std::string, Technique> Techniques;
  358.     Techniques mTechniques;
  359. };
  360.  
  361. GLCCompiler::GLCCompiler() {
  362. }
  363.  
  364. GLCCompiler::~GLCCompiler() {
  365.     while(!mFragmentShaders.empty()) {
  366.         delete mFragmentShaders.back();
  367.         mFragmentShaders.pop_back();
  368.     }
  369. }
  370.  
  371. namespace {
  372.     static const GLCKeyword sKeywordPass("pass");
  373.     static const GLCKeyword sKeywordTechnique("technique");
  374.     static const GLCKeyword sKeywordFragmentShader("fragmentshader");
  375.     static const GLCKeyword sKeywordFragment_Shader("fragment_shader");
  376.     static const GLCKeyword sKeywordNV_Register_Combiners("NV_register_combiners");
  377.     static const GLCKeyword sKeywordNV_Register_Combiners2("NV_register_combiners2");
  378.     static const GLCKeyword sKeywordATI_Fragment_Shader("ATI_fragment_shader");
  379.     static const GLCKeyword sKeywordARB_Fragment_Shader("ARB_fragment_shader");
  380. }
  381.  
  382. void GLCCompiler::Compile(const char *sourceName, const char *src, uint32 len, FILE *f) {
  383.     mpOutput = f;
  384.     mLexer.Init(sourceName, src, len);
  385.  
  386.     while(int tok = mLexer.Token()) {
  387.         if (tok == kTokenIdent) {
  388.             if (mLexer.IsKeyword(sKeywordTechnique)) {
  389.                 ParseTechnique();
  390.             } else if (mLexer.IsKeyword(sKeywordFragment_Shader)) {
  391.                 GLCFragmentShader shader;
  392.                 ParseFragmentShader(shader);
  393.                 continue;
  394.             }
  395.         }
  396.     }
  397.  
  398.     // write out fragment shaders
  399.     fputs("/////////////////////////////////////////////////////////////////////////////\n", f);
  400.     fputs("// fragment shaders\n", f);
  401.     fputs("//\n", f);
  402.     const int fragmentShaderCount = mFragmentShaders.size();
  403.  
  404.     for(int i=0; i<fragmentShaderCount; ++i) {
  405.         char buf[64];
  406.         sprintf(buf, "g_fragmentShader%d", i);
  407.  
  408.         mFragmentShaders[i]->Write(mpOutput, buf);
  409.     }
  410.  
  411.     // write out techniques
  412.     fputs("\n", f);
  413.     fputs("/////////////////////////////////////////////////////////////////////////////\n", f);
  414.     fputs("// techniques\n", f);
  415.     fputs("//\n", f);
  416.     fprintf(f, "static const struct VDOpenGLTechnique g_techniques[]={\n");
  417.     Techniques::const_iterator it(mTechniques.begin()), itEnd(mTechniques.end());
  418.     for(; it!=itEnd; ++it) {
  419.         const Technique& tech = it->second;
  420.  
  421.         int index = std::find(mFragmentShaders.begin(), mFragmentShaders.end(), tech.mpFragmentShader) - mFragmentShaders.begin();
  422.  
  423.         fprintf(f, "\t{ &g_fragmentShader%d, %s },\n", index, tech.mpFragmentShader->GetTypeString());
  424.     }
  425.     fprintf(f, "};\n");
  426.     
  427.     it = mTechniques.begin();
  428.     for(int techIndex = 0; it!=itEnd; ++it, ++techIndex) {
  429.         const char *name = it->first.c_str();
  430.  
  431.         fprintf(f, "static const int kVDOpenGLTechIndex_%s = %d;\n", name, techIndex);
  432.     }
  433.  
  434.  
  435.     printf("Asuka: %d techniques, %d fragment shaders.\n", mTechniques.size(), mFragmentShaders.size());
  436. }
  437.  
  438. namespace {
  439.     class ARBFragmentShader : public vdrefcounted<IGLCFragmentShader> {
  440.     public:
  441.         ARBFragmentShader(const char *s, int len) {
  442.             mText.assign(s, s+len);
  443.             printf("%.*s\n", len, s);
  444.         }
  445.  
  446.         const char *GetTypeString() {
  447.             return "kVDOpenGLFragmentShaderModeARBFS";
  448.         }
  449.  
  450.         void Write(FILE *f, const char *sym) {
  451.             fprintf(f, "static const char %s[]=\n", sym);
  452.  
  453.             bool open = false;
  454.             bool sol = true;
  455.             int len = mText.size();
  456.             const char *s = mText.data();
  457.  
  458.             for(int i=0; i<len; ++i) {
  459.                 char c = s[i];
  460.  
  461.                 if (!open) {
  462.                     putc('"', f);
  463.                     open = true;
  464.                 }
  465.  
  466.                 if (c == '\r')
  467.                     continue;
  468.  
  469.                 if (c == '\t')
  470.                     c = ' ';
  471.  
  472.                 if (c == ' ' && sol)
  473.                     continue;
  474.  
  475.                 if (c == '\n' || c == '\\' || c == '"')
  476.                     putc('\\', f);
  477.  
  478.                 if (c == '\n') {
  479.                     fputs("n\"\n", f);
  480.                     open = false;
  481.                     sol = true;
  482.                 } else {
  483.                     sol = false;
  484.                     putc(c, f);
  485.                 }
  486.             }
  487.  
  488.             if (open)
  489.                 fputs("\\n\"\n", f);
  490.  
  491.             fprintf(f, ";\n");
  492.         }
  493.  
  494.     public:
  495.         vdfastvector<char> mText;
  496.     };
  497. }
  498.  
  499. void GLCCompiler::ParseTechnique() {
  500.     std::string namestr;
  501.  
  502.     Expect(kTokenIdent);
  503.     const char *name = mLexer.GetToken();
  504.     namestr.assign(name, name + mLexer.GetTokenLen());
  505.  
  506.     std::pair<Techniques::iterator, bool> result(mTechniques.insert(Techniques::value_type(namestr, Technique())));
  507.  
  508.     if (!result.second)
  509.         mLexer.ThrowError("Technique '%s' already defined", namestr.c_str());
  510.  
  511.     Technique& tech = result.first->second;
  512.  
  513.     Expect('{');
  514.  
  515.     Expect(kTokenIdent);
  516.     if (!mLexer.IsKeyword(sKeywordPass))
  517.         Huh("pass declaration", kTokenIdent);
  518.  
  519.     Expect('{');
  520.  
  521.     for(;;) {
  522.         int tok = mLexer.Token();
  523.  
  524.         if (tok == '\n')
  525.             continue;
  526.         else if (tok == '}')
  527.             break;
  528.         else if (tok == kTokenIdent) {
  529.             if (mLexer.IsKeyword(sKeywordFragmentShader)) {
  530.                 Expect('=');
  531.                 Expect(kTokenIdent);
  532.                 if (mLexer.IsKeyword(sKeywordFragment_Shader)) {
  533.                     tok = mLexer.Token();
  534.  
  535.                     if (tok != kTokenIdent)
  536.                         Huh("fragment shader profile", tok);
  537.  
  538.                     enum {
  539.                         kProfileNVRC,
  540.                         kProfileNVRC2,
  541.                         kProfileATIFS,
  542.                         kProfileARBFS
  543.                     } profile;
  544.  
  545.                     if (mLexer.IsKeyword(sKeywordNV_Register_Combiners))
  546.                         profile = kProfileNVRC;
  547.                     else if (mLexer.IsKeyword(sKeywordNV_Register_Combiners2))
  548.                         profile = kProfileNVRC2;
  549.                     else if (mLexer.IsKeyword(sKeywordATI_Fragment_Shader))
  550.                         profile = kProfileATIFS;
  551.                     else if (mLexer.IsKeyword(sKeywordARB_Fragment_Shader))
  552.                         profile = kProfileARBFS;
  553.                     else
  554.                         mLexer.ThrowError("Unknown shader profile '%.*s'", mLexer.GetTokenLen(), mLexer.GetToken());
  555.  
  556.                     vdautoptr<IGLCFragmentShader> fshader;
  557.                     if (profile == kProfileARBFS) {
  558.                         Expect('{');
  559.                         mLexer.EnableForeignCode(true);
  560.                         Expect(kTokenForeignCode);
  561.                         mLexer.EnableForeignCode(false);
  562.                         fshader = new ARBFragmentShader(mLexer.GetToken(), mLexer.GetTokenLen());
  563.                         Expect('}');
  564.                     } else {
  565.                         GLCFragmentShader shader;
  566.                         ParseFragmentShader(shader);
  567.                         
  568.                         switch(profile) {
  569.                             case kProfileNVRC:
  570.                                 fshader = CompileFragmentShaderNVRegisterCombiners(mLexer, shader, false);
  571.                                 break;
  572.                             case kProfileNVRC2:
  573.                                 fshader = CompileFragmentShaderNVRegisterCombiners(mLexer, shader, true);
  574.                                 break;
  575.                             case kProfileATIFS:
  576.                                 fshader = CompileFragmentShaderATIFragmentShader(mLexer, shader);
  577.                                 break;
  578.                         }
  579.                     }
  580.  
  581.                     tech.mpFragmentShader = fshader;
  582.  
  583.                     mFragmentShaders.push_back(fshader.release());
  584.                 }
  585.                 Expect(';');
  586.                 continue;
  587.             }
  588.         }
  589.  
  590.         Huh("technique parameter", tok);
  591.     }
  592.  
  593.     Expect('}');
  594. }
  595.  
  596. void GLCCompiler::ParseFragmentShader(GLCFragmentShader& shader) {
  597.     shader.mLocation = mLexer.GetLocation();
  598.  
  599.     Expect('{');
  600.  
  601.     mLexer.EnableNewlines(true);
  602.  
  603.     bool coissue = false;
  604.     for(;;) {
  605.         int tok = mLexer.Token();
  606.  
  607.         if (tok == '+') {
  608.             coissue = true;
  609.             continue;
  610.         }
  611.  
  612.         if (tok == '}')
  613.             break;
  614.         else if (tok == '\n') {
  615.             if (coissue)
  616.                 mLexer.ThrowError("Syntax error");
  617.             continue;
  618.         } else if (tok == kTokenIdent) {
  619.             const GLCCodeLocation loc = mLexer.GetLocation();
  620.             const char *s = mLexer.GetToken();
  621.             int toklen = mLexer.GetTokenLen();
  622.             int insnlen = 0;
  623.  
  624.             // parse instruction itself
  625.             while(insnlen < toklen && s[insnlen] != '_')
  626.                 ++insnlen;
  627.  
  628.             int insn = 0;
  629.             int insn_dests = 1;
  630.             int insn_sources = 0;
  631.             switch(insnlen) {
  632.             case 2:
  633.                 if (!memcmp(s, "dd", 2)) {
  634.                     insn = kFSOpDd;
  635.                     insn_dests = 2;
  636.                     insn_sources = 4;
  637.                 }
  638.                 if (!memcmp(s, "dm", 2)) {
  639.                     insn = kFSOpDm;
  640.                     insn_dests = 2;
  641.                     insn_sources = 4;
  642.                 }
  643.                 break;
  644.             case 3:
  645.                 if (!memcmp(s, "mov", 3)) {
  646.                     insn = kFSOpMov;
  647.                     insn_sources = 1;
  648.                 } else if (!memcmp(s, "add", 3)) {
  649.                     insn = kFSOpAdd;
  650.                     insn_sources = 2;
  651.                 } else if (!memcmp(s, "sub", 3)) {
  652.                     insn = kFSOpSub;
  653.                     insn_sources = 2;
  654.                 } else if (!memcmp(s, "mul", 3)) {
  655.                     insn = kFSOpMul;
  656.                     insn_sources = 2;
  657.                 } else if (!memcmp(s, "mad", 3)) {
  658.                     insn = kFSOpMad;
  659.                     insn_sources = 3;
  660.                 } else if (!memcmp(s, "lrp", 3)) {
  661.                     insn = kFSOpLrp;
  662.                     insn_sources = 3;
  663.                 } else if (!memcmp(s, "dp3", 3)) {
  664.                     insn = kFSOpDp3;
  665.                     insn_sources = 2;
  666.                 } else if (!memcmp(s, "dp4", 3)) {
  667.                     insn = kFSOpDp4;
  668.                     insn_sources = 2;
  669.                 } else if (!memcmp(s, "dda", 3)) {
  670.                     insn = kFSOpDda;
  671.                     insn_dests = 3;
  672.                     insn_sources = 4;
  673.                 } else if (!memcmp(s, "mma", 3)) {
  674.                     insn = kFSOpMma;
  675.                     insn_dests = 3;
  676.                     insn_sources = 4;
  677.                 } else if (!memcmp(s, "def", 3)) {
  678.                     insn = kFSOpDef;
  679.                     insn_dests = 0;
  680.                     insn_sources = 4;
  681.                 }
  682.                 break;
  683.  
  684.             case 5:
  685.                 if (!memcmp(s, "final", 5)) {
  686.                     insn = kFSOpFinal;
  687.                     insn_dests = 0;
  688.                     insn_sources = 7;
  689.                 } else if (!memcmp(s, "texld", 5)) {
  690.                     insn = kFSOpTexld2Arg;
  691.                     insn_dests = 1;
  692.                     insn_sources = 1;
  693.                 } else if (!memcmp(s, "phase", 5)) {
  694.                     insn = kFSOpPhase;
  695.                     insn_dests = 0;
  696.                     insn_sources = 0;
  697.                 }
  698.                 break;
  699.  
  700.             case 6:
  701.                 if (!memcmp(s, "texcrd", 6)) {
  702.                     insn = kFSOpTexcrd;
  703.                     insn_dests = 1;
  704.                     insn_sources = 1;
  705.                 }
  706.                 break;
  707.             }
  708.  
  709.             if (!insn)
  710.                 mLexer.ThrowError("Unknown fragment shader instruction '%.*s'", insnlen, s);
  711.  
  712.             // parse modifiers
  713.             int modifiers = 0;
  714.             while(insnlen < toklen) {
  715.                 if (s[insnlen] != '_')
  716.                     mLexer.ThrowError("Syntax error in fragment shader instruction");
  717.  
  718.                 ++insnlen;
  719.  
  720.                 const char *modbase = s + insnlen;
  721.                 int modstart = insnlen;
  722.  
  723.                 while(insnlen < toklen && s[insnlen] != '_')
  724.                     ++insnlen;
  725.  
  726.                 int modlen = insnlen - modstart;
  727.                 int modbit = 0;
  728.                 switch(modlen) {
  729.                 case 2:
  730.                     if (!memcmp(modbase, "x2", 2))
  731.                         modbit = kInsnModX2;
  732.                     else if (!memcmp(modbase, "x4", 2))
  733.                         modbit = kInsnModX4;
  734.                     else if (!memcmp(modbase, "x8", 2))
  735.                         modbit = kInsnModX8;
  736.                     else if (!memcmp(modbase, "d2", 2))
  737.                         modbit = kInsnModD2;
  738.                     else if (!memcmp(modbase, "d4", 2))
  739.                         modbit = kInsnModD4;
  740.                     else if (!memcmp(modbase, "d8", 2))
  741.                         modbit = kInsnModD8;
  742.                     break;
  743.  
  744.                 case 3:
  745.                     if (!memcmp(modbase, "bx2", 3))
  746.                         modbit = kInsnModBX2;
  747.                     else if (!memcmp(modbase, "sat", 3))
  748.                         modbit = kInsnModSat;
  749.                     break;
  750.  
  751.                 case 4:
  752.                     if (!memcmp(modbase, "bias", 4))
  753.                         modbit = kInsnModBias;
  754.                     break;
  755.                 }
  756.  
  757.                 if (!modbit)
  758.                     mLexer.ThrowError("Invalid instruction modifier '%.*s'", modlen, modbase);
  759.  
  760.                 modifiers |= modbit;
  761.             }
  762.  
  763.             // def is special
  764.             if (insn == kFSOpDef) {
  765.                 if (modifiers)
  766.                     mLexer.ThrowError("'def' instruction cannot have modifiers");
  767.  
  768.                 if (coissue)
  769.                     mLexer.ThrowError("'def' instruction cannot be co-issued");
  770.  
  771.                 GLCDestArg arg = ParseFragmentShaderDestination();
  772.  
  773.                 if (arg.mWriteMask != 15 || (arg.mReg & kRegTypeMask) != kRegC0)
  774.                     mLexer.ThrowError("'def' must be used with a full constant register");
  775.  
  776.                 int index = arg.mReg - kRegC0;
  777.  
  778.                 if (shader.mUsedConstants & (1 << index))
  779.                     mLexer.ThrowError("Constant 'c%d' already defined", index);
  780.  
  781.                 shader.mUsedConstants |= (1 << index);
  782.  
  783.                 for(int i=0; i<4; ++i) {
  784.                     Expect(',');
  785.                     shader.mConstants[arg.mReg - kRegC0][i] = (float)ParseConstantDoubleExpression();
  786.                 }
  787.             } else {
  788.                 GLCFragmentOp op={0};
  789.  
  790.                 op.mInsn = insn;
  791.                 op.mModifiers = modifiers;
  792.                 op.mbCoIssue = coissue;
  793.                 coissue = false;
  794.  
  795.                 // parse destinations
  796.                 for(int i=0; i<insn_dests; ++i) {
  797.                     if (i)
  798.                         Expect(',');
  799.  
  800.                     op.mDstArgs[i] = ParseFragmentShaderDestination();
  801.                     if ((op.mDstArgs[i].mReg & kRegTypeMask) == kRegC0)
  802.                         mLexer.ThrowError("Constant registers cannot be used as destinations");
  803.                 }
  804.  
  805.                 // parse sources
  806.                 for(int i=0; i<insn_sources; ++i) {
  807.                     if (i || insn_dests)
  808.                         Expect(',');
  809.                     op.mSrcArgs[i] = ParseFragmentShaderArgument();
  810.                 }
  811.  
  812.                 op.mLocation = loc;
  813.  
  814.                 Expect('\n');
  815.  
  816.                 shader.mOps.push_back(op);
  817.             }
  818.             continue;
  819.         }
  820.  
  821.         Huh("fragment shader instruction", tok);
  822.     }
  823.  
  824.     mLexer.EnableNewlines(false);
  825. }
  826.  
  827. GLCDestArg GLCCompiler::ParseFragmentShaderDestination() {
  828.     GLCDestArg arg;
  829.  
  830.     int tok = mLexer.Token();
  831.  
  832.     if (tok != kTokenIdent)
  833.         Huh("fragment shader register", tok);
  834.  
  835.     // parse out base register
  836.     const char *s = mLexer.GetToken();
  837.     int namelen = mLexer.GetTokenLen();
  838.  
  839.     if (memchr(s, '_', namelen))
  840.         mLexer.ThrowError("Destination register cannot have modifier");
  841.  
  842.     arg.mReg = 0;
  843.     if (namelen == 7 && !memcmp(s, "discard", 7)) {
  844.         arg.mReg = kRegDiscard;
  845.     } else {
  846.         unsigned index = 0;
  847.  
  848.         for(int i=1; i<namelen; ++i) {
  849.             if (!isdigit((unsigned char)s[i]))
  850.                 goto invalid_register;
  851.  
  852.             index = (index * 10) + (s[i] - '0');
  853.         }
  854.  
  855.         if (s[0] == 't') {
  856.             if (index >= 6)
  857.                 mLexer.ThrowError("Invalid texture register '%.*s'", namelen, s);
  858.             arg.mReg = kRegT0 + index;
  859.         } else if (s[0] == 'r') {
  860.             if (index >= 6)
  861.                 mLexer.ThrowError("Invalid spare register '%.*s'", namelen, s);
  862.             arg.mReg = kRegR0 + index;
  863.         } else if (s[0] == 'c') {
  864.             if (index >= 16)
  865.                 mLexer.ThrowError("Invalid constant register '%.*s'", namelen, s);
  866.             arg.mReg = kRegC0 + index;
  867.         } else if (s[0] == 'v') {
  868.             if (index >= 2)
  869.                 mLexer.ThrowError("Invalid vertex interpolator register '%.*s'", namelen, s);
  870.             arg.mReg = kRegV0 + index;
  871.         }
  872.     }
  873.  
  874.     if (!arg.mReg) {
  875. invalid_register:
  876.         mLexer.ThrowError("Unknown fragment shader destination register '%.*s'", namelen, s);
  877.     }
  878.  
  879.     // parse out write mask
  880.     tok = mLexer.Token();
  881.  
  882.     arg.mWriteMask = 15;
  883.     if (tok == '.') {
  884.         tok = mLexer.Token();
  885.  
  886.         if (tok != kTokenIdent)
  887.             Huh("register write mask", tok);
  888.  
  889.         const char *s = mLexer.GetToken();
  890.         int len = mLexer.GetTokenLen();
  891.  
  892.         arg.mWriteMask = 0;
  893.         for(int i=0; i<len; ++i) {
  894.             int bit;
  895.  
  896.             switch(s[i]) {
  897.                 case 'r':
  898.                     bit = 1;
  899.                     break;
  900.                 case 'g':
  901.                     bit = 2;
  902.                     break;
  903.                 case 'b':
  904.                     bit = 4;
  905.                     break;
  906.                 case 'a':
  907.                     bit = 8;
  908.                     break;
  909.  
  910.                 default:
  911. invalid_write_mask:
  912.                     mLexer.ThrowError("Invalid destination write mask");
  913.             }
  914.  
  915.             if ((arg.mWriteMask & bit) || bit < arg.mWriteMask)
  916.                 goto invalid_write_mask;
  917.  
  918.             arg.mWriteMask |= bit;
  919.         }
  920.     } else {
  921.         mLexer.Push(tok);
  922.     }
  923.  
  924.     return arg;
  925. }
  926.  
  927. GLCSourceArg GLCCompiler::ParseFragmentShaderArgument() {
  928.     GLCSourceArg arg;
  929.     int tok = mLexer.Token();
  930.  
  931.     // parse out complement and negation modifiers
  932.     arg.mMods = 0;
  933.     for(;;) {
  934.         if (tok == '-')
  935.             arg.mMods ^= kRegModNegate;
  936.         else if (tok == kTokenInteger) {
  937.             if (mLexer.GetInteger() != 1)
  938.                 mLexer.ThrowError("Invalid register modifier");
  939.  
  940.             Expect('-');
  941.  
  942.             arg.mMods |= kRegModComplement;
  943.         } else
  944.             break;
  945.  
  946.         tok = mLexer.Token();
  947.     }
  948.  
  949.     if (tok != kTokenIdent)
  950.         Huh("fragment shader register", tok);
  951.  
  952.     // parse out base register
  953.     const char *s = mLexer.GetToken();
  954.     int toklen = mLexer.GetTokenLen();
  955.     int namelen = 0;
  956.  
  957.     // parse instruction itself
  958.     while(namelen < toklen && s[namelen] != '_')
  959.         ++namelen;
  960.  
  961.     arg.mReg = 0;
  962.     if (namelen == 4 && !memcmp(s, "zero", 4)) {
  963.         arg.mReg = kRegZero;
  964.     } else if (namelen == 7 && !memcmp(s, "discard", 7)) {
  965.         mLexer.ThrowError("'discard' cannot be used in a source argument");
  966.     } else {
  967.         unsigned index = 0;
  968.  
  969.         for(int i=1; i<namelen; ++i) {
  970.             if (!isdigit((unsigned char)s[i]))
  971.                 goto invalid_register;
  972.  
  973.             index = (index * 10) + (s[i] - '0');
  974.         }
  975.  
  976.         if (s[0] == 't') {
  977.             if (index >= 6)
  978.                 mLexer.ThrowError("Invalid texture register '%.*s'", namelen, s);
  979.             arg.mReg = kRegT0 + index;
  980.         } else if (s[0] == 'r') {
  981.             if (index >= 6)
  982.                 mLexer.ThrowError("Invalid spare register '%.*s'", namelen, s);
  983.             arg.mReg = kRegR0 + index;
  984.         } else if (s[0] == 'c') {
  985.             if (index >= 16)
  986.                 mLexer.ThrowError("Invalid constant register '%.*s'", namelen, s);
  987.             arg.mReg = kRegC0 + index;
  988.         } else if (s[0] == 'v') {
  989.             if (index >= 2)
  990.                 mLexer.ThrowError("Invalid vertex interpolator register '%.*s'", namelen, s);
  991.             arg.mReg = kRegV0 + index;
  992.         }
  993.     }
  994.  
  995.     if (!arg.mReg) {
  996. invalid_register:
  997.         mLexer.ThrowError("Unknown fragment shader register '%.*s'", namelen, s);
  998.     }
  999.  
  1000.     // parse modifiers
  1001.     while(namelen < toklen) {
  1002.         if (s[namelen] != '_')
  1003.             mLexer.ThrowError("Syntax error in fragment shader register");
  1004.  
  1005.         ++namelen;
  1006.  
  1007.         const char *modbase = s + namelen;
  1008.         int modstart = namelen;
  1009.  
  1010.         while(namelen < toklen && s[namelen] != '_')
  1011.             ++namelen;
  1012.  
  1013.         int modlen = namelen - modstart;
  1014.         int modbit = 0;
  1015.         switch(modlen) {
  1016.         case 2:
  1017.             if (!memcmp(modbase, "x2", 2))
  1018.                 modbit = kRegModX2;
  1019.             break;
  1020.         case 3:
  1021.             if (!memcmp(modbase, "bx2", 3))
  1022.                 modbit = kRegModBias | kRegModX2;
  1023.             else if (!memcmp(modbase, "sat", 3))
  1024.                 modbit = kRegModSaturate;
  1025.             break;
  1026.  
  1027.         case 4:
  1028.             if (!memcmp(modbase, "bias", 4))
  1029.                 modbit = kRegModBias;
  1030.             break;
  1031.         }
  1032.  
  1033.         if (!modbit)
  1034.             mLexer.ThrowError("Invalid register modifier '%.*s'", modlen, modbase);
  1035.  
  1036.         arg.mMods |= modbit;
  1037.     }
  1038.  
  1039.     tok = mLexer.Token();
  1040.  
  1041.     arg.mSwizzle = kSwizzleNone;
  1042.     arg.mSize = 4;
  1043.     if (tok == '.') {
  1044.         tok = mLexer.Token();
  1045.  
  1046.         if (tok != kTokenIdent)
  1047.             Huh("register swizzle", tok);
  1048.  
  1049.         const char *s = mLexer.GetToken();
  1050.         int len = mLexer.GetTokenLen();
  1051.  
  1052.         arg.mSwizzle = 0;
  1053.         arg.mSize = 0;
  1054.         for(int i=0; i<len; ++i) {
  1055.             int component;
  1056.  
  1057.             switch(s[i]) {
  1058.                 case 'r':
  1059.                     component = 0;
  1060.                     break;
  1061.                 case 'g':
  1062.                     component = 1;
  1063.                     break;
  1064.                 case 'b':
  1065.                     component = 2;
  1066.                     break;
  1067.                 case 'a':
  1068.                     component = 3;
  1069.                     break;
  1070.  
  1071.                 default:
  1072. invalid_swizzle:
  1073.                     mLexer.ThrowError("Invalid register swizzle");
  1074.             }
  1075.  
  1076.             arg.mSwizzle += component << (2*i);
  1077.             ++arg.mSize;
  1078.             if (arg.mSize >= 4)
  1079.                 goto invalid_swizzle;
  1080.         }
  1081.  
  1082.         // .a/r/g/b -> .aaaa/rrrr/gggg/bbbb
  1083.         if (arg.mSize == 1) {
  1084.             arg.mSize = 4;
  1085.             arg.mSwizzle *= 0x55;
  1086.         }
  1087.     } else {
  1088.         mLexer.Push(tok);
  1089.     }
  1090.  
  1091.     return arg;
  1092. }
  1093.  
  1094. double GLCCompiler::ParseConstantDoubleExpression() {
  1095.     vdfastvector<double> mValueStack;
  1096.     vdfastvector<int> mOpStack;
  1097.     int parensValue = 0;
  1098.     bool needValue = true;
  1099.  
  1100.     for(;;) {
  1101.         int tok = mLexer.Token();
  1102.  
  1103.         if (needValue) {
  1104.             if (tok == '(')
  1105.                 parensValue += 0x1000000;
  1106.             else if (tok == '-')
  1107.                 mOpStack.push_back(parensValue + 'N' + 0x60000);
  1108.             else if (tok == kTokenInteger) {
  1109.                 mValueStack.push_back(mLexer.GetInteger());
  1110.                 needValue = false;
  1111.             } else if (tok == kTokenDouble) {
  1112.                 mValueStack.push_back(mLexer.GetDouble());
  1113.                 needValue = false;
  1114.             } else if (tok != '+')
  1115.                 Huh("numeric value", tok);
  1116.         } else {
  1117.             int opValue;
  1118.  
  1119.             if (tok == ')' && parensValue) {
  1120.                 parensValue -= 0x1000000;
  1121.                 continue;
  1122.             }
  1123.  
  1124.             if (tok == '+')
  1125.                 opValue = parensValue + tok + 0x10000;
  1126.             else if (tok == '-')
  1127.                 opValue = parensValue + tok + 0x10000;
  1128.             else if (tok == '*')
  1129.                 opValue = parensValue + tok + 0x20000;
  1130.             else if (tok == '/')
  1131.                 opValue = parensValue + tok + 0x20000;
  1132.             else if (tok == ';' || tok == ',' || tok == ')' || tok == '\n') {
  1133.                 if (parensValue)
  1134.                     mLexer.ThrowError("Unmatched ')'");
  1135.  
  1136.                 mLexer.Push(tok);
  1137.                 opValue = 0;
  1138.             } else
  1139.                 Huh("expression operator", tok);
  1140.  
  1141.             while(!mOpStack.empty() && (mOpStack.back() & 0xffff0000) >= (opValue & 0xffff0000)) {
  1142.                 int op = mOpStack.back() & 0xffff;
  1143.                 mOpStack.pop_back();
  1144.  
  1145.                 double y;
  1146.                 switch(op) {
  1147.                     case '+':
  1148.                         y = mValueStack.back();
  1149.                         mValueStack.pop_back();
  1150.                         mValueStack.back() += y;
  1151.                         break;
  1152.                     case '-':
  1153.                         y = mValueStack.back();
  1154.                         mValueStack.pop_back();
  1155.                         mValueStack.back() -= y;
  1156.                         break;
  1157.                     case '*':
  1158.                         y = mValueStack.back();
  1159.                         mValueStack.pop_back();
  1160.                         mValueStack.back() *= y;
  1161.                         break;
  1162.                     case '/':
  1163.                         y = mValueStack.back();
  1164.                         if (y == 0.0f)
  1165.                             mLexer.ThrowError("Division by zero");
  1166.                         mValueStack.pop_back();
  1167.                         mValueStack.back() /= y;
  1168.                         break;
  1169.                     case 'N':
  1170.                         mValueStack.back() = -mValueStack.back();
  1171.                         break;
  1172.                 }
  1173.             }
  1174.  
  1175.             mOpStack.push_back(opValue);
  1176.  
  1177.             if (!opValue)
  1178.                 break;
  1179.  
  1180.             needValue = true;
  1181.         }
  1182.     }
  1183.  
  1184.     VDASSERT(mValueStack.size() == 1);
  1185.     return mValueStack.back();
  1186. }
  1187.  
  1188. void GLCCompiler::Expect(int c) {
  1189.     int tok = mLexer.Token();
  1190.  
  1191.     if (c != tok)
  1192.         mLexer.ThrowError("Expected '%s', found '%s'", TokenName(c).c_str(), TokenName(tok).c_str());
  1193. }
  1194.  
  1195. void GLCCompiler::Huh(const char *expected, int found) {
  1196.     mLexer.ThrowError("Expected %s, found '%s'", expected, TokenName(found).c_str());
  1197. }
  1198.  
  1199. std::string GLCCompiler::TokenName(int tok) {
  1200.     switch(tok) {
  1201.     case kTokenIdent:
  1202.         return "identifier";
  1203.  
  1204.     case kTokenInteger:
  1205.         return "integer";
  1206.  
  1207.     case kTokenDouble:
  1208.         return "real";
  1209.  
  1210.     case kTokenForeignCode:
  1211.         return "foreign code";
  1212.  
  1213.     case '\n':
  1214.         return "end-of-line";
  1215.  
  1216.     default:
  1217.         {
  1218.             char buf[2]= { (char)tok, 0 };
  1219.             return buf;
  1220.         }
  1221.         break;
  1222.     }
  1223. }
  1224.  
  1225. ///////////////////////////////////////////////////////////////////////////////
  1226. void tool_glc(const vdfastvector<const char *>& args, const vdfastvector<const char *>& switches) {
  1227.     if (args.size() < 2) {
  1228.         printf("usage: glc <binary file> <.cpp output file>\n");
  1229.         exit(5);
  1230.     }
  1231.  
  1232.     printf("Asuka: Compiling effect file (OpenGL): %s -> %s.\n", args[0], args[1]);
  1233.  
  1234.     FILE *f = fopen(args[0], "rb");
  1235.     if (!f)
  1236.         fail("    couldn't open: %s\n", args[0]);
  1237.     fseek(f, 0, SEEK_END);
  1238.     size_t l = ftell(f);
  1239.     vdfastvector<char> buf(l);
  1240.     fseek(f, 0, SEEK_SET);
  1241.     if (!buf.empty())
  1242.         fread(&buf[0], l, 1, f);
  1243.     fclose(f);
  1244.  
  1245.     f = fopen(args[1], "w");
  1246.     if (!f)
  1247.         fail("    couldn't open: %s\n", args[1]);
  1248.  
  1249.     fprintf(f, "// Automatically generated by Asuka from \"%s.\" DO NOT EDIT!\n\n", VDFileSplitPath(args[0]));
  1250.  
  1251.     GLCCompiler glc;
  1252.  
  1253.     glc.Compile(args[0], buf.data(), buf.size(), f);
  1254.  
  1255.     fclose(f);
  1256.  
  1257.     printf("Asuka: Compilation was successful.\n");
  1258. }
  1259.